package com.esint.lombok;

import com.esint.lombok.*;
import com.esint.lombok.car.*;
import lombok.extern.java.Log;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;

import java.util.Random;
import java.util.UUID;

/**
 * @description: lombok 测试类
 * @author: 谷明
 * @createDate: 2021/8/12 14:17
 */
//@Log
@Slf4j
public class TestLombok {
    public static void main(String[] args) {
        /* 将讨论以下属性作用：
         * @Getter和@Setter
         * @ToString
         * @EqualsAndHashCode
         * @Data
         * @Accessors
         * @Builder
         * @Log和@Slf4j
         */

        /*
            无参构造函数，当类上有@AllArgsConstructor的时候，必须加上@NoArgsConstructor注解。
            当没有当类上没有@AllArgsConstructor的时候，不用加，
            所以有文章里说@Data = @Setter+@Getter+@NoArgsConstructor注解，其实@Data作用并不包含@NoArgsConstructor，
            如果包含，那么当类上有@Data和@AllArgsConstructor的时候，就不用加@NoArgsConstructor了
        * */
        Person person = new Person();
        /*
         * @Data起作用
         */
        person.setName("豆豆");
        person.setAge(18);
        person.setIdNo("41041119880607351X");
        person.setGender(1);
        person.setHobby("吃饭、睡觉");
        System.out.println("豆豆的年龄是："+person.getAge());

        /*
          @AllArgsConstructor自动生成
         */
        Person person1 = new Person("jack", 1, 10, "41041119880607351X", "吃饭睡觉打豆豆");
        /*
         * @RequiredArgsConstructor 起作用 我理解是快速实现单例模式的一种方式
         */
        ThePerson theOne = ThePerson.GetTheOne();
        // 这么写会报错，因为构造函数已经私有化
        //ThePerson theOne = new ThePerson();
        /*
         * 从结果可以看出，当存在@RequiredArgsConstructor 的时候，@AllArgsConstructor已经没有什么意义了，直接调用不到
         */
        System.out.println(theOne);

        Person2 p2 = new Person2("小红", 0, 19, "41041119880607352X", "看书、旅游");
        System.out.println("Person2实例（ToString方法只输出name和age）：" + p2);
        //不写Getter和Setter的不能修改
        //p2.setHobby("听歌，打篮球");
        //p2.getHobby("听歌，打篮球");
        p2.setIdNo("41041119880607353X");
        //因为IdNo只有Setter，没有Getter，所以不能获取值
        //p2.getIdNo();

        /*
         * @EqualsAndHashCode 注解：判断对象在业务上是否相等
         * Person3类上只有@Data，没有@EqualsAndHashCode注解，说明@Data默认包含@EqualsAndHashCode
         */
        Person3 p3_1 = new Person3("大壮", 1, 22, "41041119880607354X", "打篮球、踢足球");
        Person3 p3_2 = new Person3("大壮", 1, 22, "41041119880607354X", "打篮球、踢足球");
        Person2 p2_1 = new Person2("大壮", 1, 22, "41041119880607354X", "打篮球、踢足球");

        System.out.println("同类型equels比较结果：" + p3_1.equals(p3_2));
        System.out.println("不同类型字段相同equels比较结果：" + p3_1.equals(p2_1));

        /*
         * 使用 exclude 和 of 参数配置比较的属性，在类上调整注释测试这两个参数发挥的作用
         */
        Person4 p4_1 = new Person4(UUID.randomUUID().toString(), new Random().nextInt(100), "大壮", 1, 22, "41041119880607354X", "打篮球、踢足球");
        Person4 p4_2 = new Person4(UUID.randomUUID().toString(), new Random().nextInt(100), "大壮", 1, 22, "41041119880607354X", "打篮球、踢足球");
        System.out.println("指定属性比较："+ p4_1.equals(p4_2));

        /*
         * @Accessors
         * fluent 作用：直接字段名作为getter和setter方法名，且setter方法返回对象，可以链式调用来设置对象值
         * chain 作用：单独设置setter方法返回对象，可以链式调用来设置对象值
         * prefix 作用：去掉指定前缀，如果想去掉前缀，必须是 [小写（要去掉的前缀）][首字母大写] 格式的，或者[前缀_][要保留的部分]
         */
        Person5 p5 = new Person5();
        p5.gender(1).name("大壮").hobby("吃饭睡觉打豆豆");
        System.out.println("p5：" + p5);

        /*
         * @Builder
         * 其实我理解这个注解的主要作用是快速实现建造者模式的最终组装类的组装功能的，因此这里我拿汽车来举例
         * 建造者模式：https://blog.csdn.net/lovelion/article/details/7426015
         */
        Engine engine = new Engine("DXIIA123123123334545", "V8", 900);
        OutsideShell outsideShell = new OutsideShell("blue", "s1");
        Seats seats = new Seats("真皮");
        SteeringWheel steeringWheel = new SteeringWheel("round", "Aluminium", true);
        Territory territory = new Territory("stainless steel", "t3", false);
        Wheels wheels = new Wheels(14F, 70F);
        //建造者模式组装汽车类
        Car car = Car.builder().engine(engine).outsideShell(outsideShell).seats(seats).steeringWheel(steeringWheel).territory(territory).wheels(wheels).build();
        System.out.println("建造者模式获得的Car对象："+ car);

        log.error("测试日志输出");
    }
}
